#ifndef _GOVT_STAT_H
#define _GOVT_STAT_H
/*******************************************************************************
 ** Name: stat.h                                                              **
 ** Description:                                                              **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved 2-clause BSD License                             **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  Redistribution and use in source and binary forms, with or without       **
 **  modification, are permitted provided that the following conditions are   **
 **  met:                                                                     **
 **                                                                           **
 **  * Redistributions of source code must retain the above copyright notice, **
 **    this list of conditions and the following disclaimer.                  **
 **  * Redistributions in binary form must reproduce the above copyright      **
 **    notice, this list of conditions and the following disclaimer in the    **
 **    documentation and/or other materials provided with the distribution.   **
 **                                                                           **
 **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS      **
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED **
 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           **
 ** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT        **
 ** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
 **                                                                           **
 ******************************************************************************/
// Modified $Date: 2011-09-18 21:48:59 +0000 (Sun, 18 Sep 2011) $ by $Author: gian.james $
#define _stat_h_ID    "$Id: stat.hpp 145 2011-09-18 21:48:59Z gian.james $"
#include "common.hpp"

#define BASE_STAT_MAX		26	// the highest level a primary stat can get
#define BASE_STAT_START		8	// base stats start off at 8
#define DEFAULT_STARTING_POINTS		30

//! for use in the rest of the game to reference a statistic from one location
//! use:  stat::base::str, or  stat::save::reflex, or stat::derived::def
namespace stat
{
    enum class base { str, dex, con, intel, wis, cha, max };
    enum class derived { hp, def, init, bab, mab, rab, speed, rep, ap, wealth, max };
    enum class save { fort, reflex, will, recovery, max };
    // stats have a current, modifier, and temp (the mod is not the temp mod)
    enum class which { curr, mod, temp, max };
    enum class hp { max, curr };
    enum class speed { max, curr };
}

//! The base stat/attributes for every character
class BaseStat
{
public:
    BaseStat();
    /////////////////////////// Fetch/Set Methods
    // Get normal statistic
    int      STR() const { return stats[(uint8)stat::base::str][(uint8)stat::which::curr]; }
    int      CON() const { return stats[(uint8)stat::base::con][(uint8)stat::which::curr]; }
    int      DEX() const { return stats[(uint8)stat::base::dex][(uint8)stat::which::curr]; }
    int      INT() const { return stats[(uint8)stat::base::intel][(uint8)stat::which::curr]; }
    int      WIS() const { return stats[(uint8)stat::base::wis][(uint8)stat::which::curr]; }
    int      CHA() const { return stats[(uint8)stat::base::cha][(uint8)stat::which::curr]; }
    // Get modifier
    int    modSTR() const { return stats[(uint8)stat::base::str][(uint8)stat::which::mod]; }
    int    modCON() const { return stats[(uint8)stat::base::con][(uint8)stat::which::mod]; }
    int    modDEX() const { return stats[(uint8)stat::base::dex][(uint8)stat::which::mod]; }
    int    modINT() const { return stats[(uint8)stat::base::intel][(uint8)stat::which::mod]; }
    int    modWIS() const { return stats[(uint8)stat::base::wis][(uint8)stat::which::mod]; }
    int    modCHA() const { return stats[(uint8)stat::base::cha][(uint8)stat::which::mod]; }
    // Get temporary statistic (buff, debuff, etc)
    int    tempSTR() const { return stats[(uint8)stat::base::str][(uint8)stat::which::temp]; }
    int    tempCON() const { return stats[(uint8)stat::base::con][(uint8)stat::which::temp]; }
    int    tempDEX() const { return stats[(uint8)stat::base::dex][(uint8)stat::which::temp]; }
    int    tempINT() const { return stats[(uint8)stat::base::intel][(uint8)stat::which::temp]; }
    int    tempWIS() const { return stats[(uint8)stat::base::wis][(uint8)stat::which::temp]; }
    int    tempCHA() const { return stats[(uint8)stat::base::cha][(uint8)stat::which::temp]; }

    // Set normal statistic
    void    CON(const int s) { stats[(uint8)stat::base::con][(uint8)stat::which::curr]= s; }
    void    DEX(const int s) { stats[(uint8)stat::base::dex][(uint8)stat::which::curr]= s; }
    void    INT(const int s) { stats[(uint8)stat::base::intel][(uint8)stat::which::curr]= s; }
    void    WIS(const int s) { stats[(uint8)stat::base::wis][(uint8)stat::which::curr]= s; }
    void    CHA(const int s) { stats[(uint8)stat::base::cha][(uint8)stat::which::curr]= s; }
    // Set modifier

    void    modSTR(const int s) { stats[(uint8)stat::base::str][(uint8)stat::which::mod]= s; }
    void    modCON(const int s) { stats[(uint8)stat::base::con][(uint8)stat::which::mod]= s; }
    void    modDEX(const int s) { stats[(uint8)stat::base::dex][(uint8)stat::which::mod]= s; }
    void    modINT(const int s) { stats[(uint8)stat::base::intel][(uint8)stat::which::mod]= s; }
    void    modWIS(const int s) { stats[(uint8)stat::base::wis][(uint8)stat::which::mod]= s; }
    void    modCHA(const int s) { stats[(uint8)stat::base::cha][(uint8)stat::which::mod]= s; }

    // Set temporary statistic (buff, debuff, etc)

    void    tempSTR(const int s) {  stats[(uint8)stat::base::str][(uint8)stat::which::temp]= s; }
    void    tempCON(const int s) {  stats[(uint8)stat::base::con][(uint8)stat::which::temp]= s; }
    void    tempDEX(const int s) {  stats[(uint8)stat::base::dex][(uint8)stat::which::temp]= s; }
    void    tempINT(const int s) {  stats[(uint8)stat::base::intel][(uint8)stat::which::temp]= s; }
    void    tempWIS(const int s) {  stats[(uint8)stat::base::wis][(uint8)stat::which::temp]= s; }
    void    tempCHA(const int s) {  stats[(uint8)stat::base::cha][(uint8)stat::which::temp]= s; }


    static inline const char * ToString(stat::base s);
    static  int       Bonus(const int s) { return ((s/2)-5); }
	void		PrintStat(stat::base s, char * buff);

private:
    int     stats[(int)stat::base::max][(int)stat::which::max];

};

//! Attributes that are derived from other stats
// I'm not sure if these should be indexed or individual members.
class   DerivedStat
{
public:
    DerivedStat();
    
     int  BAB() const { return bab; }
     int  RAB() const { return rab; }
     int  MAB() const { return mab; }
     int  Speed() const { return speed[0]; }
     int  maxSpeed() const { return speed[1]; }
     int  Defense() const { return def; }
     int  Initiative() const { return initiative; }
     int  HP() const { return hp[0]; }
     int  maxHP() const { return hp[1]; }
     int  EP() const { return ep; }

     void     BAB(int v) { bab = v; }
     void     RAB(int v) { rab = v; }
     void     MAB(int v) { mab = v; }
     void     Speed(int v) { speed[0] = v; }
     void     maxSpeed(int v) { speed[1] = v; }
     void     Defense(int v) { def = v; }
     void     Initiative(int v) { initiative = v; }
     void     HP(int v) { hp[0] = v; }
     void	incrHP(const int h) { if (hp[0] += h, hp[0] > hp[1]) hp[0] = hp[1]; }
     int 	decrHP(const int h) { if (hp[0] -= h, hp[0] <= 0) hp[0] = 0; return 0; }
     void     maxHP(int v) { hp[1] = v; }
     void     EP(int e) { ep = e; }

    static inline const char *   ToString(stat::derived s);


    
private:
    int     initiative;
    int     hp[2];
    int     speed[2];
    int     bab;
    int     mab;
    int     rab;
    int     def;
    int     ep;     //!< endurance points. Only used if astral-sensitive.
};

//! Collects saving throws in one location. Four saving throws.
class   SavingThrow
{
public:
    SavingThrow();

     int  Fortitude() const { return saves[(uint8)stat::save::fort]; }
     int  Reflex() const { return saves[(uint8)stat::save::reflex]; }
     int  Will() const { return saves[(uint8)stat::save::will]; }
     int  Recovery() const { return saves[(uint8)stat::save::recovery]; }

     void Fortitude(int v) { saves[(uint8)stat::save::fort] = v; }
     void Reflex(int v) { saves[(uint8)stat::save::reflex] = v; }
     void Will(int v) { saves[(uint8)stat::save::will] = v; }
     void Recovery(int v) { saves[(uint8)stat::save::recovery] = v; }

    static inline const char *   ToString(stat::save s);

private:
    int     saves[(uint8)stat::save::max];
};



namespace stat	/* namespace stat */
{


//-> This is unwieldy and should change in the future.
////////////////////////////////////[ Stat Modifiers
//! Any stat that can get modified is listed here.
enum statsmod
{
    str, dex, con, intl, wis, cha,
    def, init, speed, bab, rab, mab, rep, wealth, ap,
    fort, reflex, will, recovery, hp,
    //////////// skills
    attention, business, chemistry, computers, deception,
    engineering, firearms, influence, intuition, investigation,
    leadership, law, linguistics, listen, magic, math, medicine,
    meld, mutant, nature, search, stealth, streetwise, stunts,
    tradecraft, unarmed, vehicles, weapons,
    ///////// skillchecks
    fabricateWriting, knowledgeAcademic, research,
    fabricateArt, knowledgeArt, ForgeryArt,
    climb, jump, run, swim, notice, economics, embezzlement, haggle,
    launder, fabricateChemBasic, fabricateChemExplosives,
    fabricateChemMeds, fabricateChemPainMeds, fabricateChemSedatives,
    fabricateChemSteroids, fabricateChemSerums, fabricateChemStims,
    fabricateChemPoisons, knowledgeChem, fabricateComputer,
    knowledgeComputer, disableComputer, stealthComputer, evadeComputer,
    coverupComputer, repairComputer, operateComputer, optimizeComputer,
    disguise, forgery, concealAction, fabricateElectronics,
    knowledgeElectronics, disableElectronics, operateElectronics,
    repairElectronics, optimizeElectronics,
    fabricateMechanical, knowledgeMechanical, disableMechanical,
    operateMechanical, repairMechanical, optimizeMechanical,
    fabricateArch, knowledgeArch, disableArch, repairArch,
    fabricateFirearm, knowledgeFirearm, operateFirearm,
    repairFirearm, bluff, diplomacy, intimidate, bribe, revealTruth,
    appraise, analyze, authenticate, forensics, teamwork, communication,
    competence, noretreat, knowledgeLaw, rwLang, speakLang, comprehendLang,
    decipherLing, hear,
    // magic TODO
    knowledgeArcane, arcaneBestiary, spellcasting,
    encryptData, decryptData, cipher, decipherMath, paramedic, critcare,
    ems, pharma, surgery, blend,
    // mutant TODO
    precognition, translocate,
    survival, orienteering, tracking, animalHandling, ride, stealthNature,
    spot, hide, movesilently, connections, knowledgeStreet, gambling,
    bribeStreet, stealthUrban, balance, escape, parachute, tumble,
    disableSecurity, lockpick,
    // unarmed TODO
    unarmedDisarm, punch, kick, grapple, jointlock, push, trip, block,
    drive, maneuver, stealthVehicle, evadeVehicle, chase, pilot, repairVehicle,
    // weapons TODO
    wpnDisarm, wpnProf, wpnFinesse, parry,

    /////////// actions


    max
};
extern const char *    stat2str[];

#define INCREASES   1
#define DECREASES   0

//! The structure elucidating stat modifications.
struct	StatMod
{
    StatMod() { thisStat = statsmod::max; updown = 1; mod = cause = 0; next = NULL; }
    statsmod	thisStat;	//!< the stat this modifier modifies
    int         updown;     //!< increases or decreases
    int16       mod;		//!< by this amount
    StatMod *   next;
    uint32      cause;      //!< ID/Flag of item that gets bonus
};

}	/* namespace stat */

#endif	/* GOVT_STAT_H */

